#include "AspectEngine.h"

namespace agtk {

MRTManager::MRTManager(void)
{
	glGenFramebuffersEXT(1, &m_fboHandle);
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboHandle);

	// Set up depth buffer
	glGenRenderbuffersEXT(1, &m_depthBufferHandle);
	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBufferHandle);
	glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, g_aspectEngine->GetWidth(), g_aspectEngine->GetHeight());
	glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBufferHandle);

	// Set up RT0
	glGenTextures(1, &m_RT0Handle);
	glBindTexture(GL_TEXTURE_2D, m_RT0Handle);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  g_aspectEngine->GetWidth(), g_aspectEngine->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_RT0Handle, 0);

	// Set up RT1
	glGenTextures(1, &m_RT1Handle);
	glBindTexture(GL_TEXTURE_2D, m_RT1Handle);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  g_aspectEngine->GetWidth(), g_aspectEngine->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, m_RT1Handle, 0);

	// Set up RT2
	glGenTextures(1, &m_RT2Handle);
	glBindTexture(GL_TEXTURE_2D, m_RT2Handle);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  g_aspectEngine->GetWidth(), g_aspectEngine->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT, GL_TEXTURE_2D, m_RT2Handle, 0);

	// Set up RT3
	glGenTextures(1, &m_RT3Handle);
	glBindTexture(GL_TEXTURE_2D, m_RT3Handle);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,  g_aspectEngine->GetWidth(), g_aspectEngine->GetHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT3_EXT, GL_TEXTURE_2D, m_RT3Handle, 0);

	GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT };
	glDrawBuffers(3, buffers);

	GLenum status;
    status=(GLenum)glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
    switch(status) {
        case GL_FRAMEBUFFER_COMPLETE_EXT:
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
            printf("Framebuffer incomplete,incomplete attachment\n");
            break;
        case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
            printf("Unsupported framebuffer format\n");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
            printf("Framebuffer incomplete,missing attachment\n");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
            printf("Framebuffer incomplete,attached images must have same dimensions\n");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
             printf("Framebuffer incomplete,attached images must have same format\n");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
            printf("Framebuffer incomplete,missing draw buffer\n");
            break;
        case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
            printf("Framebuffer incomplete,missing read buffer\n");
            break;
    }

	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

MRTManager::~MRTManager(void)
{
}

void MRTManager::BindFBO(void)
{
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fboHandle);
}

void MRTManager::UnbindFBO(void)
{
	glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
}

GLuint MRTManager::GetRT(unsigned int id)
{
	switch(id) {
		case 0:
			return m_RT0Handle;
			break;
		case 1:
			return m_RT1Handle;
			break;
		case 2:
			return m_RT2Handle;
			break;
		case 3:
			return m_RT3Handle;
			break;
		default:
			return 0;
	}
}

GLuint MRTManager::GetDepthBuffer(void)
{
	return m_depthBufferHandle;
}

void MRTManager::BindRenderTextures(void)
{
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindTexture(GL_TEXTURE_2D, m_RT0Handle);
	glActiveTexture(GL_TEXTURE1);
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindTexture(GL_TEXTURE_2D, m_RT1Handle);
	glActiveTexture(GL_TEXTURE2);
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindTexture(GL_TEXTURE_2D, m_RT2Handle);
	glActiveTexture(GL_TEXTURE3);
	glBindTexture(GL_TEXTURE_2D, 0);
	glBindTexture(GL_TEXTURE_2D, m_RT3Handle);
}

}